package com.yuandian.business.monitor.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuandian.api.business_monitor.po.SystemOverviewParams;
import com.yuandian.api.business_monitor.vo.*;
import com.yuandian.api.management.entity.ConfSystem;
import com.yuandian.api.management.feign.RemoteBusinessService;
import com.yuandian.api.management.feign.RemoteSystemService;
import com.yuandian.base.service.ITaskDataService;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.business.monitor.mapper.AppSystemMapper;
import com.yuandian.business.monitor.service.IAppSystemService;
import com.yuandian.business.monitor.service.IUserOperationsService;
import com.yuandian.constant.Constants;
import com.yuandian.enums.BaseTableName;
import com.yuandian.enums.ScaleTypeEnum;
import com.yuandian.po.BaseSearch;
import com.yuandian.po.MergeDataConfig;
import com.yuandian.po.MergeField;
import com.yuandian.utils.*;
import com.yuandian.utils.poi.ExcelUtil;
import com.yuandian.vo.TrendDataVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
 * 说明：应用系统service实现
 *
 * @Author yanjun
 * @Date 2020/9/21 14:42
 */
@Service
@Slf4j
public class AppSystemServiceImpl implements IAppSystemService {

	@Autowired
	private AppSystemMapper appSystemMapper;

//    @Autowired
//    private ISynchronousBusinessService synchronousBusinessService;

	@Autowired
	private IUserOperationsService userOperationsService;

	@Autowired
	private ITaskDataService taskDataService;
	@Autowired
	private RemoteSystemService remoteSystemService;
	@Autowired
	private RemoteBusinessService remoteBusinessService;

	/**
	 * 查询应用系统列表
	 *
	 * @param appSystemVo 应用系统vo对象
	 * @param page        分页参数
	 * @return 应用系统列表
	 */
	@Override
	public PageDataInfo appSystemList(AppSystemVo appSystemVo, Page<AppSystemVo> page) {
		List<AppSystemVo> asVoList = new ArrayList<>();
//        List<AppSystemVo> asVoList = appSystemMapper.appSystemList(appSystemVo, page);
		ConfSystem confSystem = new ConfSystem();
//		page = remoteSystemService.listPage(confSystem).getData();
		if (page == null) {
			return new PageDataInfo(asVoList.size(), asVoList);
		}
		return new PageDataInfo(page, asVoList);
	}

	/**
	 * 查询关键系统TOP5
	 *
	 * @return 应用系统vo对象集合
	 */
	@Override
	public R queryKeySystemTop5() {
		ConfSystem confSystem = new ConfSystem();
		confSystem.setStatus(1);
		confSystem.setIsKey(1);
		confSystem.setPageNum(1);
		confSystem.setPageSize(5);
		confSystem.setOrderByColumn("sequence");
		return remoteSystemService.listPage(confSystem);
	}


	/**
	 * 系统健康度,平均处理时长,告警请求量趋势图
	 *
	 * @param params
	 * @return
	 */
	@Override
	public TrendDataVo systemTrendList(SystemOverviewParams params) {
		//查询的结束时间不能大于统计时间
		params.setEndTime(taskDataService.getTrendObject(BaseTableName.BUSI_SYS_REQ_TREND.getName(), params.getStartTime(), params.getEndTime(), null).getTrendEndTime());
		String startTimeStr = params.getStartTime();
		String endTimeStr = params.getEndTime();

		List<SystemReqTrendVo> list = appSystemMapper.systemTrendList(params);

		// 5、归并数据
		List<MergeField> mergeFieldList = new ArrayList<>();
		mergeFieldList.add(new MergeField("reqCount"));
		mergeFieldList.add(new MergeField("alarmCount"));
		mergeFieldList.add(new MergeField("totalDealTime"));
		mergeFieldList.add(new MergeField("totalServerResponseTime"));
		Map<String, Object> map = MergeDataUtil.mergeData(new MergeDataConfig.Builder(
				SystemReqTrendVo.class,
				list,
				params.getStartTime(),
				params.getEndTime(),
				mergeFieldList)
				.cycleTimeKey("labelTime")
				.labelTimeFormatter("MM-dd'\n'HH:mm")
				.scale(params.getScale())
				.build());

		Map<String, Object> resFieldMap = (Map<String, Object>) map.get("resFieldMap");
		resFieldMap.put("healthRateList", new ArrayList<>());
		resFieldMap.put("avgServerResponseTimeList", new ArrayList<>());
		List<Object> alarmCountList = (List<Object>) resFieldMap.get("alarmCountList");
		List<Object> reqCountList = (List<Object>) resFieldMap.get("reqCountList");
		List<Object> totalServerResponseTimeList = (List<Object>) resFieldMap.get("totalServerResponseTimeList");
		List<Object> healthRateList = (List<Object>) resFieldMap.get("healthRateList");
		List<Object> avgServerResponseTimeList = (List<Object>) resFieldMap.get("avgServerResponseTimeList");


		for (int i = 0; i < alarmCountList.size(); i++) {
			if ((double) reqCountList.get(i) == 0D) {
				avgServerResponseTimeList.add(0D);
				healthRateList.add(0D);
			} else {
				avgServerResponseTimeList.add((double) totalServerResponseTimeList.get(i) / (double) reqCountList.get(i));
				healthRateList.add(Double.valueOf(new BigDecimal((((double) reqCountList.get(i) - (double) alarmCountList.get(i)) / (double) reqCountList.get(i) * 100))
						.setScale(2, RoundingMode.HALF_UP).toString()));
			}
		}

		// 计算周平均、月平均、历史峰值
		String endTime = YDateUtil.format(new Date(), Constants.YYYY_MM_DD_00_00_00);
		String weekStartTime = YDateUtil.getBeforeDayTime(endTime, 7);
		params.setStartTime(weekStartTime);
		params.setEndTime(endTime);
		int weekAvgValue = appSystemMapper.queryAvgIndicatorValue(params);	// 周平均值

		String monthStartTime = YDateUtil.getBeforeDayTime(endTime, 30);
		params.setStartTime(monthStartTime);
		int monthAvgValue = appSystemMapper.queryAvgIndicatorValue(params);	// 月平均值
		BusinessAvgAndPeakVo avgAndPeakVo = new BusinessAvgAndPeakVo();

		// 历史峰值
		params.setStartTime(startTimeStr);
		params.setEndTime(endTimeStr);
		queryPeakValue(avgAndPeakVo, params);

		avgAndPeakVo.setWeekAvgValue(weekAvgValue);
		avgAndPeakVo.setWeekStartTime(weekStartTime);
		avgAndPeakVo.setWeekEndTime(endTime);
		avgAndPeakVo.setMonthAvgValue(monthAvgValue);
		avgAndPeakVo.setMonthStartTime(monthStartTime);
		avgAndPeakVo.setMonthEndTime(endTime);

		resFieldMap.put("avgAndPeakVo", avgAndPeakVo);

		/**
		 * 将任务的任务名称、查询的开始时间、查询的结束时间，趋势图数组或者对象传到此方法里，此方法会计算趋势图的开始时间、结束时间，
		 * 并返回一个包装类，不会对趋势图数组或者对象进行加工
		 */
		TrendDataVo trendDataVo = taskDataService.getTrendObject(BaseTableName.BUSI_SYS_REQ_TREND.getName(), params.getStartTime(), params.getEndTime(), map);
		return trendDataVo;
	}

	/**
	 * 查询历史峰值
	 * @param avgAndPeakVo 结果对象
	 * @param params	请求参数
	 */
	public void queryPeakValue(BusinessAvgAndPeakVo avgAndPeakVo, SystemOverviewParams params) {


		long startTime = System.currentTimeMillis();
		long peakValue = 0; int scale = 1;
		ExecutorService executor = null;
		String peakStartTime = "", scaleType = ScaleTypeEnum.DAY.name();

		try {
			String endTime = YDateUtil.format(new Date(), Constants.YYYY_MM_DD_00_00_00);
			List<BaseSearch> timeIntervalList = PartitionUtil.getTimeIntervalList(endTime, 5, 20);
			List<Callable<BusinessAvgAndPeakVo>> tasks = new ArrayList<>();

			// 查询数据
			for (BaseSearch timeInterval : timeIntervalList) {
				tasks.add(() -> appSystemMapper.queryPeakValue(params, scale, scaleType, timeInterval));
			}
			executor = Executors.newFixedThreadPool(tasks.size());
			List<Future<BusinessAvgAndPeakVo>> futures = executor.invokeAll(tasks);

			// 封装数据
			for (Future<BusinessAvgAndPeakVo> future : futures) {
				BusinessAvgAndPeakVo peakVo = future.get();
				if (peakVo != null && peakVo.getPeakValue() > peakValue) {
					peakValue = peakVo.getPeakValue();
					peakStartTime = peakVo.getPeakStartTime();
				}
			}

			avgAndPeakVo.setPeakValue(peakValue);
			avgAndPeakVo.setPeakStartTime(StringUtils.isNotEmpty(peakStartTime) ? (peakStartTime + " 00:00:00") : null);
			if (StringUtils.isNotEmpty(peakStartTime)) {
				avgAndPeakVo.setPeakEndTime(YDateUtil.getAfterDay(peakStartTime + " 00:00:00", scale));
			}

			log.info("[BPM模块]-[系统监控详情-获取 访问量 历史峰值 信息]-耗时: {} MS", System.currentTimeMillis() - startTime);

		} catch (Exception e) {
			e.printStackTrace();
			log.error("[BPM模块]-[系统监控详情-获取 访问量 历史峰值 信息]-报错: {}", e.getMessage());

		} finally {
			if (executor != null) { executor.shutdown(); }
		}

	}

	/**
	 * 下载全系统总览
	 *
	 * @param params
	 * @return
	 */
	@Override
	public void downloadSystemOverview(SystemOverviewParams params, HttpServletResponse response) throws IOException {
		List<SystemOverviewVo> systemOverviewVos = new ArrayList<>();
		params.setPageNum(1);
		params.setPageSize(-1);
		//根据排序字段判断是以哪个表为主表进行排序(默认为系统请求量趋势表为主表)
		PageDataInfo result = querySystemOverview(params);
		if (result != null) {
			systemOverviewVos = BeanUtils.cast(result.getData());
		}
		//设置id
		int index = 1;
		DecimalFormat df = new DecimalFormat("0.00");
		for (SystemOverviewVo vo : systemOverviewVos) {
			vo.setId(index++);
			//添加%
			vo.setHealthRateStr(vo.getHealthRate() + "%");
			vo.setSuccessRateStr(vo.getSuccessRate() + "%");
			//处理平均处理时长
			vo.setAvgDealTimeStr((vo.getAvgDealTime() == null || vo.getAvgDealTime() == 0) ? "0.00ms" : df.format((double) vo.getAvgDealTime() / 1000) + "ms");
		}
		//excel主标题,如"全系统监控总览列表  2021-12-17 10:00:00 ~ 2021-12-17 11:00:00"
		String formTitleName = "全系统监控总览列表" + Constants.DOUBLE_SPACE + params.getStartTime() + "~" + params.getEndTime();
		//列标题
		List<List<String>> headList = new ArrayList<>();
		List<String> titleList = Arrays.asList("序号", "系统名称", "监控业务数", "平均响应耗时", "访问量", "失败访问量", "告警访问量", "请求总数", "告警请求", "失败请求", "成功率", "健康度");
		titleList.forEach(s -> {
			List<String> childHeadList = new ArrayList<>();
			childHeadList.add(formTitleName);
			childHeadList.add(s);
			headList.add(childHeadList);
		});
		ExcelUtil.writeExcel(SystemOverviewVo.class, formTitleName, "全系统监控总览列表", systemOverviewVos, headList, response);
	}

	/**
	 * 全系统总览列表
	 *
	 * @param params
	 * @return
	 */
	@Override
	public PageDataInfo querySystemOverview(SystemOverviewParams params) {
		// 1、获取表信息集,
//        String visitTable = BaseTableName.BUSI_SYS_VISIT_TREND.getName();
//        String reqTable = BaseTableName.BUSI_SYS_REQ_TREND.getName();

		// 3、设置表信息集，默认排序
		if (ObjectUtil.isEmpty(params.getOrderByColumn())) {
			params.setOrderByColumn("visitCount");
			params.setIsAsc("desc");
		}
		// 4、执行查询
		IPage<SystemOverviewVo> systemReqDataOverviewPage = appSystemMapper.querySystemOverview(new Page<>(params.getPageNum(),
				params.getPageSize()), params);
		//获取系统Id集合
		List<Integer> systemIds = systemReqDataOverviewPage.getRecords().stream().map(SystemOverviewVo::getId).collect(Collectors.toList());
		//通过系统id集合获取每个系统对应的业务数
		Map<Integer, Integer> businessCountMap = new HashMap<>();
		if(ObjectUtil.isNotEmpty(systemIds)){
			List<Map<String, Integer>> data = remoteBusinessService.getBusinessCountBySystemIds(systemIds).getData();
			data.forEach(e -> businessCountMap.put(e.get("systemId"), e.get("businessCount")));
		}
		// 5、转换业务数据
		DecimalFormat df = new DecimalFormat("0.00");
		for (SystemOverviewVo record : systemReqDataOverviewPage.getRecords()) {
			//转换健康度和成功率的格式,保留小数点后两位
			record.setHealthRateStr(df.format((double) record.getHealthRate()));
			record.setSuccessRateStr(df.format((double) record.getSuccessRate()));
			//回填业务个数
			record.setBusinessCount(businessCountMap.get(record.getId()));
			//访问量为空时,告警访问量和失败访问量都设为0
			if (record.getVisitCount() == null) {
				record.setVisitCount(0);
				record.setAlarmVisitCount(0);
				record.setFailVisitCount(0);
			}
		}
		// 6、返回分页对象
		return new PageDataInfo(systemReqDataOverviewPage);
	}

	/**
	 * 全系统统计详情
	 *
	 * @param params
	 * @return
	 */
	@Override
	public List<SystemOverviewVo> querySystemStatisticsDetail(SystemOverviewParams params) {

		IPage<SystemOverviewVo> systemReqDataOverviewPage = appSystemMapper.querySystemStatisticsDetail(new Page<>(1, -1), params);
		List<SystemOverviewVo> systemOverviewVos = systemReqDataOverviewPage.getRecords().stream().filter(s -> s.getId() .equals(params.getSystemId())).collect(Collectors.toList());
		DecimalFormat df = new DecimalFormat("0.00");
		for (SystemOverviewVo record : systemOverviewVos) {
			record.setHealthRateStr((record.getHealthRate() == null || record.getHealthRate() == 0) ? "0.00" : df.format((double) record.getHealthRate()));
			record.setSuccessRateStr((record.getSuccessRate() == null || record.getSuccessRate() == 0) ? "0.00" : df.format((double) record.getSuccessRate()));

			if (record.getVisitCount() == null) {
				record.setVisitCount(0);
				record.setAlarmVisitCount(0);
				record.setFailVisitCount(0);
			}
		}
		return systemOverviewVos;
	}

	/**
	 * 查询用户数
	 *
	 * @param params
	 * @return
	 */
	@Override
	public HashMap<String, Integer> queryUserNum(SystemOverviewParams params) {
		int userCount = userOperationsService.queryBusiUserCount(params.getStartTime(), params.getEndTime(), params.getSystemId(), "");
		HashMap<String, Integer> map = new HashMap<>();
		map.put("userNum", userCount);
		return map;
	}

	/**
	 * 查询异常用户数
	 *
	 * @param params
	 * @return
	 */
	@Override
	public HashMap<String, Integer> queryExceptionUserNum(SystemOverviewParams params) {
		int count = userOperationsService.queryBusiUserExcepitonCount(params.getStartTime(), params.getEndTime(), params.getSystemId(), "");
		HashMap<String, Integer> map = new HashMap<>();
		map.put("exceptionUserNum", count);
		return map;
	}
}
